package com.ddxz.middleground.master.service.impl;

import com.ddxz.middleground.master.dto.MasterHeader;
import com.ddxz.middleground.master.dto.dept.Department;
import com.ddxz.middleground.master.dto.dept.DepartmentDetail;
import com.ddxz.middleground.master.dto.dept.DeptInfo;
import com.ddxz.middleground.master.entity.DepartmentEntity;
import com.ddxz.middleground.master.mapper.DepartmentMapper;
import com.ddxz.middleground.master.mapper.UserMapper;
import com.ddxz.middleground.master.service.DepartmentService;
import com.ddxz.middleground.master.util.ErrorStatus;
import com.ddxz.tool.core.common.CommonUtil;
import com.ddxz.tool.core.common.DdxzTree;
import com.ddxz.tool.core.common.DdxzTreeUtil;
import com.ddxz.tool.core.convert.BeanUtil;
import com.ddxz.tool.core.convert.CollectionUtil;
import com.ddxz.tool.core.convert.DdxzUtil;
import com.ddxz.tool.core.convert.StringUtil;
import com.ddxz.tool.web.common.ConstData;
import com.ddxz.tool.web.dto.DdxzResponse;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import static com.ddxz.middleground.master.util.ErrorStatus.*;

/**
 * class description
 *
 * @author 朱宗刚
 * @version 1.0.0
 * @date 2020/7/26
 */

@Service
public class DepartmentServiceImpl implements DepartmentService, DdxzTreeUtil {
    public DepartmentServiceImpl(DepartmentMapper deptMapper, UserMapper userMapper) {
        this.deptMapper = deptMapper;
        this.userMapper = userMapper;
    }

    @Override
    public DdxzResponse deptList(MasterHeader header, String keyword) {
        List<String> deptIds = new LinkedList<>();
        deptIds.add("-1");
        List<DepartmentEntity> deptEntityList;
        List<Department> tmps;
        List<DdxzTree> result = new ArrayList<>();
        while (!CollectionUtil.isEmpty(deptIds)) {
            deptEntityList = deptMapper.getDeptByParent(deptIds.get(0), header.getTenant());
            tmps = new ArrayList<>(deptEntityList.size());
            deptEntityList.forEach(dept -> deptIds.add(dept.getId()));
            CollectionUtil.copyCollection(deptEntityList, tmps, Department.class, DdxzUtil.SECOND_DATE);
            if (CollectionUtil.isEmpty(result)) {
                result.addAll(tmps);
            } else {
                findItem(result, deptIds.get(0)).getChildren().addAll(tmps);
            }
            deptIds.remove(0);
        }

        if (StringUtil.isEmpty(keyword)) {
            return DdxzResponse.correct(result);
        } else {
            return DdxzResponse.correct(treeFilter(result, keyword));
        }
    }

    @Override
    public DdxzResponse deptDetail(String deptId, MasterHeader header) {
        DepartmentEntity entity = deptMapper.getDetail(deptId, header.getTenant());
        CommonUtil.ddxzAssetNull(entity, DEPT_NOT_EXISTS);
        return DdxzResponse.correct(BeanUtil.getTarget(entity, DepartmentDetail.class, DdxzUtil.SECOND_DATETIME));
    }

    @Override
    public DdxzResponse deptSave(MasterHeader header, DeptInfo deptReq) {
        checkStatus(deptReq.getStatus());
        DepartmentEntity entity = new DepartmentEntity();
        if (StringUtil.isEmpty(deptReq.getId())) {
            // 新增部门时，保证部门名称在同一个上级部门下不重复。
            Integer num = deptMapper.getNumByName(deptReq.getName(), deptReq.getCode(), deptReq.getParentId(), header.getTenant());
            CommonUtil.ddxzAssetGreat(num, 0, DEPT_NAME_REPEAT);

            num = deptMapper.getSubNum(deptReq.getParentId(), header.getTenant());
            BeanUtil.copyProperties(deptReq, entity);
            entity.setId(CommonUtil.generatorId(T_DEPARTMENT));
            entity.setCreator(header.getNickname());
            entity.setOrder(num + 1);
            entity.setUserId(header.getUserId());
            deptMapper.saveDept(entity, header.getTenant());
        } else {
            BeanUtil.copyProperties(deptReq, entity);
            deptMapper.modifyDept(entity, header.getTenant());
        }
        return DdxzResponse.correct("保存部门成功", entity.getId());
    }

    @Override
    public DdxzResponse deptDelete(MasterHeader header, String deptId) {
        Integer num = deptMapper.getSubNum(deptId, header.getTenant());
        CommonUtil.ddxzAssetGreat(num, 0, DEPT_NOT_EMPTY);

        num = userMapper.getNumByDeptId(deptId, header.getTenant());
        CommonUtil.ddxzAssetGreat(num, 0, DEPT_HAS_EMPLOYEE);

        deptMapper.removeDept(deptId, header.getTenant());
        return DdxzResponse.correct("删除部门成功", ConstData.OK_MESSAGE);
    }

    @Override
    public DdxzResponse deptMove(String deptId, Integer direction, MasterHeader header) {
        DepartmentEntity entity = deptMapper.getDetail(deptId, header.getTenant());
        switch (direction) {
            case UP:
                // 上移，获取当前显示序号，如果为1则报错，置顶的无法上移；将序号减1同时将原上一序号的部门序号加1
                return moveUp(entity, header.getTenant());
            case DOWN:
                // 下移，获取当前显示序号，当前总数，如果相等则报错，至底无法下移；否则序号加1元下一序号部门序号减1
                return moveDown(entity, header.getTenant());
            case INCREASE:
                // 升级；获取上级部门A序号和标识；如果上级序号为-1，顶级部门，无法上移；否则获取A的上级B标识和A的兄弟部门数；
                // 将当前部门的上级标识修改为B，序号为A兄弟部门的最大值加1；修改当前部门兄弟部门的序号
                return moveIncrease(entity, header.getTenant());
            case DECREASE:
                // 降级：获取当前序号，如果为1则报错；否则获取前一个序号的部门标识，获取前一个部门下子部门的个数；修改其他兄弟节点的序号
                return moveDecrease(entity, header.getTenant());
            default:
                return DdxzResponse.error(ErrorStatus.INVALID_DIRECTION);
        }
    }

    private DdxzResponse moveIncrease(DepartmentEntity entity, String tenant) {
        CommonUtil.ddxzAssetEqual(entity.getParentId(), TOP_NODE_PARENT_ID, CANNOT_INC);
        // 获取entity上级部门的上级部门ppId，获取ppId下子部门个数num
        String ppid = deptMapper.getParentId(entity.getParentId(), tenant);
        Integer num = deptMapper.getSubNum(ppid, tenant);
        // 修改order大于entity.order的部门序号为原order-1
        deptMapper.updateBatchOrder(entity.getParentId(), entity.getOrder(), tenant);
        // 修改entity的order为num + 1；parentId为ppId
        entity.setOrder(num + 1);
        entity.setParentId(ppid);
        deptMapper.updateOrderById(entity, entity.getOrder(), tenant);
        return DdxzResponse.correct("部门升级成功", entity.getId());
    }

    private DdxzResponse moveDecrease(DepartmentEntity entity, String tenant) {
        CommonUtil.ddxzAssetLess(entity.getOrder(), MIN_DECREASE_ORDER, CANNOT_DEC);
        // 获取order为entity.order-1的部门aId；获取aId下子部门个数num
        String npid = deptMapper.getIdByOrder(entity.getParentId(), entity.getOrder() - 1, tenant);
        Integer num = deptMapper.getSubNum(npid, tenant);
        // 修改order大于order的部门序号为原order-1
        deptMapper.updateBatchOrder(entity.getParentId(), entity.getOrder(), tenant);
        // 修改entity的order为num + 1, parentId 为aId
        entity.setParentId(npid);
        entity.setOrder(num + 1);
        deptMapper.updateOrderById(entity, entity.getOrder(), tenant);
        return DdxzResponse.correct("部门降级成功", entity.getId());
    }

    private DdxzResponse moveDown(DepartmentEntity entity, String tenant) {
        int size = deptMapper.getSubNum(entity.getParentId(), tenant);
        CommonUtil.ddxzAssetUnless(entity.getOrder(), size, CANNOT_DOWN);
        // 将order为entity.order+1的部门序号修改为entity.order
        deptMapper.updateOrderByOrder(entity.getParentId(), entity.getOrder() + 1, entity.getOrder(), tenant);
        // 将entity的order修改为order+1
        deptMapper.updateOrderById(entity, entity.getOrder() + 1, tenant);
        return DdxzResponse.correct("部门下移成功", entity.getId());
    }

    private DdxzResponse moveUp(DepartmentEntity entity, String tenant) {
        CommonUtil.ddxzAssetEqual(entity.getOrder(), CANNOT_UP_ORDER, CANNOT_UP);
        // 将order为entity.order-1的部门序号修改为entity.order
        deptMapper.updateOrderByOrder(entity.getParentId(), entity.getOrder() - 1, entity.getOrder(), tenant);
        // 将entity的order修改为order-1;
        deptMapper.updateOrderById(entity, entity.getOrder() - 1, tenant);
        return DdxzResponse.correct("部门上移成功", entity.getId());
    }

    private final DepartmentMapper deptMapper;

    private final UserMapper userMapper;
}
